/*
 * Copyright (c) 2006-2021, JingJia Micro ltd.
 * 
 * License: Apache-2.0
 * 
 * File: gp_timer.c
 * Desc: generic purpose timer implement.
 * 
 * Change Logs:
 * Date             Author                 Notes
 * 2021-07-25       romix                  The first version
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "common.h"
#include "gp_timer.h"

/**
 * @brief Init table and add first entry
 *
 * @param table the table object
 * @param entry add entry
 * @param timer the table object
 * @param hook add entry
 * 
 */
static int timer_start_handle(gp_timer_t *timer)
{
    if (NULL == timer) {
        assert(timer);
        return ERROR;
    }

    if (ERROR == timer_settime(timer->id, 0, &(timer->it), NULL)) {
        fprintf(stderr, "timer settime failed.");
        return ERROR;
    }  

    return OKAY;
}

/**
 * @brief Init table and add first entry
 *
 * @param table the table object
 * @param entry add entry
 * @param timer the table object
 * @param hook add entry
 */
static int timer_stop_handle(gp_timer_t *timer)
{
    struct itimerspec it;

    it.it_interval.tv_sec = 0;
    it.it_interval.tv_nsec = 0; 
    it.it_value.tv_sec = 0;
    it.it_value.tv_nsec = 0; 

    if (NULL == timer) {
        assert(timer);
        return ERROR;
    }

    if (ERROR == timer_settime(timer->id, 0, &it, NULL)) {
        fprintf(stderr, "timer settime failed.");
        return ERROR;
    }  

    return OKAY;
}

/**
 * @brief Init table and add first entry
 *
 * @param table the table object
 * @param entry add entry
 * @param timer the table object
 * @param hook add entry
 */
static int timer_gettime_handle(gp_timer_t *timer, struct itimerspec *curr_value)
{
    if (NULL == timer) {
        assert(timer);
        return ERROR;
    }

    if (OKAY != timer_gettime(timer->id, curr_value)) {
        fprintf(stderr, "get timer time failed.");
        return ERROR;
    }

    return OKAY;
}

/**
 * @brief Init table and add first entry
 *
 * @param table the table object
 * @param entry add entry
 * @param timer the table object
 * @param hook add entry
 */
gp_timer_t *create_timer(void (*handle)(union sigval v), \
                            struct itimerspec it, char *name, void *data)
{
    gp_timer_t *timer = NULL;

    timer = (gp_timer_t *)malloc(sizeof(gp_timer_t));
    if (NULL == timer) {
        fprintf(stderr, "malloc timer failed.");
        return NULL;
    }

    memset(&timer->evp, 0, sizeof(struct sigevent));
    if (NULL != data) 
        timer->evp.sigev_value.sival_ptr = data;
    else 
        timer->evp.sigev_value.sival_ptr = timer;

    timer->evp.sigev_notify = SIGEV_THREAD;
    timer->evp.sigev_notify_function = handle;

    timer->it.it_interval.tv_sec = it.it_interval.tv_sec;
    timer->it.it_interval.tv_nsec = it.it_interval.tv_nsec; 
    timer->it.it_value.tv_sec = it.it_value.tv_sec;
    timer->it.it_value.tv_nsec = it.it_value.tv_nsec;

    timer->start = timer_start_handle;
    timer->stop = timer_stop_handle;
    timer->gettime = timer_gettime_handle;

    strcpy(timer->name, name);

    if (-1 == timer_create(CLOCK_REALTIME, &timer->evp, &timer->id)) {
        fprintf(stderr, "timer create failed.");
        return NULL;
    }

    return timer;
}

/**
 * @brief Init table and add first entry
 *
 * @param table the table object
 * @param entry add entry
 * @param timer the table object
 * @param hook add entry
 */
int delete_timer(gp_timer_t *timer)
{
    if (NULL == timer) {
        assert(timer);
        return ERROR;
    }

    if (OKAY != timer->stop(timer)) {
        fprintf(stderr, "timer stop failed.");
        return ERROR;
    }

    if (OKAY != timer_delete(timer->id)) {
        fprintf(stderr, "timer delete failed.");
        return ERROR;
    }

    free(timer);
    timer = NULL;

    return OKAY;
}